//This software module was originally developed by TelecomParisTech in the
//course of the development of MPEG-U Widgets (ISO/IEC 23007-1) standard.
//
//This software module is an implementation of a part of one or 
//more MPEG-U Widgets (ISO/IEC 23007-1) tools as specified by the MPEG-U Widgets
//(ISO/IEC 23007-1) standard. ISO/IEC gives users of the MPEG-U Widgets
//(ISO/IEC 23007-1) free license to this software module or modifications
//thereof for use in hardware or software products claiming conformance to
//the MPEG-U Widgets (ISO/IEC 23007-1). Those intending to use this software
//module in hardware or software products are advised that its use may
//infringe existing patents.
//The original developer of this software module and his/her company, the
//subsequent editors and their companies, and ISO/IEC have no liability 
//for use of this software module or modifications thereof in an implementation. 
//Copyright is not released for non MPEG-U Widgets (ISO/IEC 23007-1) conforming 
//products. 
//Telecom ParisTech retains full right to use the code for his/her own purpose, 
//assign or donate the code to a third party and to inhibit third parties from 
//using the code for non MPEG-U Widgets (ISO/IEC 23007-1) conforming products. 
//
//This copyright notice must be included in all copies or derivative works.
//
//Copyright (c) 2009.
//
/////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////
//
//	Authors:	
//					Jean Le Feuvre, Telecom ParisTech
//
/////////////////////////////////////////////////////////////////////////////////

// 01122011 AMD1 startWidget implemented
// TODO AMD1 listWidgets getWidget requestCapabilitiesList

//Initialize the main UI script
function initialize() {
    //var icon;
    var i, count, wid;

    gpac.caption = 'MPEG-U @ Osmo4';

    display_width = parseInt(gpac.get_option('Widgets', 'LastWMWidth'));
    display_height = parseInt(gpac.get_option('Widgets', 'LastWMHeight'));
    
    if (display_width && display_height) {
     gpac.set_size(display_width, display_height);
    } else {
     display_width = gpac.get_screen_width();
     display_height = gpac.get_screen_height();
    }

    //request event listeners on the window - GPAC specific extensions !!!     
    root.addEventListener('resize', on_resize, 0);
    root.addEventListener('zoom', on_zoom, 0);
    root.addEventListener('scroll', on_scroll, 0);

    widget_default_size = 200;
    scene_width = 0;
    
    wctl_iconsize = new SFVec2f(24, 24);
    icon_size = 48;
    dock_height = 48;
    info_height = 32;
    toggle_bar_height = 16;
    screen_dpi = gpac.get_horizontal_dpi();
     
    widget_remote_candidate = null;
    has_upnp = eval("(typeof(UPnP) != 'undefined');");
    if (has_upnp) {
     UPnP.onMediaRendererAdd = onMediaRendererAdd;
     UPnP.onMediaConnect = onMediaConnect;
     UPnP.BindRenderer();
     upnp_renders = null;
    }
     
    /*setup dock*/
    widget_screen_visible = false;
        
    /*widget subtree*/
    widget_display = new SFNode('Transform2D');
    ui_root.children[0] = widget_display;  

    /*widget manager page*/
    widget_screen = new SFNode('Layer2D');
    ui_root.children[1] = widget_screen;  
    
    /*all other UI elements subtree*/
    dlg_display = new SFNode('Transform2D');
    ui_root.children[2] = dlg_display;  

    infobar = text_label('', 'MIDDLE');
    ui_root.children[3] = infobar;

    /*our dock*/
    dock = new SFNode('Transform2D');
    ui_root.children[4] = dock;  
        
    /*init the widget manager*/
    Browser.loadScript('mpegu-core.js', true);
    log_level = l_inf;
    widget_manager_init();

    WidgetManager.on_widget_remove = widget_remove;
    WidgetManager.on_widget_add = widget_insert;
    WidgetManager.coreOutSetSize = widget_request_size;
    WidgetManager.coreOutShow = widget_request_show;
    WidgetManager.coreOutHide = widget_request_hide;
    WidgetManager.coreOutRequestActivate = widget_request_activate;
    WidgetManager.coreOutRequestDeactivate = widget_request_deactivate;
    WidgetManager.coreOutShowNotification = widget_request_notification;
    WidgetManager.coreOutPlaceComponent = widget_place_component;
    WidgetManager.coreOutGetAttention = widget_request_attention;
    WidgetManager.coreOutInstallWidget = widget_install_widget;
    WidgetManager.coreOutMigrateComponent = widget_migrate_component;
    WidgetManager.coreOutRequestMigrationTargets = widget_request_migration_targets;

    nb_widgets_on_screen = 0;
    first_visible_widget = 0;
    setup_icons();
    
    /*restore our widgets*/    
    widgets_init();

    //let's do the layout   
    layout();
}

function new_timeout(time)
{
 var obj = new SFNode('TimeSensor');
 
 obj.cycleInterval = time;
 obj.start = function(when) {
  var t = this.getTime();
  this.startTime = when + this.getTime();
 };
 obj.stop = function(when) {
  this.stopTime = when + this.getTime();
 };
 obj.on_event = null;
 obj.event = function(val) {
  if (this.on_event) this.on_event(val);
 };
 Browser.addRoute(obj, 'fraction_changed', obj, obj.event); 
 return obj;
}

function rectangle()
{
  var obj = new SFNode('Shape');

  obj.appearance = new SFNode('Appearance');
  obj.appearance.material = new SFNode('Material2D');
  obj.appearance.material.filled = TRUE;
  obj.appearance.material.emissiveColor = new SFColor(0.7, 0.7, 0.8);
  obj.appearance.material.lineProps = new SFNode('LineProperties');
  obj.appearance.material.lineProps.width = 2;
  obj.appearance.material.lineProps.lineColor = new SFColor(0, 0, 0);

  obj.geometry = new SFNode('Curve2D');
  obj.geometry.point = new SFNode('Coordinate2D');
  temp = obj.geometry.type;
  temp[0] = 7;
  temp[1] = 1;
  temp[2] = 7;
  temp[3] = 1;
  temp[4] = 7;
  temp[5] = 1;
  temp[6] = 7;
  temp[7] = 6;/*close*/

  obj.set_size = function(w, h) {
   var hw, hh, rx, ry;
   var temp;
   hw = w/2;
   hh = h/2;

   /*compute default rx/ry*/   
   ry = rx = 10;
   if ( (2*rx>=hw) || (2*ry>=hh)) rx = ry = 6;

   temp = this.geometry.point.point;
   temp[0] = new SFVec2f(hw-rx, hh);
   temp[1] = new SFVec2f(hw, hh);/*bezier ctrl point*/
   temp[2] = new SFVec2f(hw, hh-ry);
   temp[3] = new SFVec2f(hw, -hh+ry);
   temp[4] = new SFVec2f(hw, -hh);/*bezier control point*/
   temp[5] = new SFVec2f(hw-rx, -hh);
   temp[6] = new SFVec2f(-hw+rx, -hh);
   temp[7] = new SFVec2f(-hw, -hh);/*bezier control point*/
   temp[8] = new SFVec2f(-hw, -hh+ry);
   temp[9] = new SFVec2f(-hw, hh-ry);
   temp[10] = new SFVec2f(-hw, hh);/*bezier control point*/
   temp[11] = new SFVec2f(-hw+rx, hh);
  };
  obj.set_color = function(r, g, b) {
   this.appearance.material.emissiveColor.r = r;
   this.appearance.material.emissiveColor.g = g;
   this.appearance.material.emissiveColor.b = b;
  };
  return obj;
}

function icon_button(url, label, no_back)
{
    var obj = new SFNode('Transform2D');
    obj.children[0] = new SFNode('Transform2D');
    obj.children[0].scale.x = 0;
    obj.children[0].children[0] = rectangle();
    
    obj.children[1] = new SFNode('Layer2D');
    obj.children[1].size.x = icon_size;
    obj.children[1].size.y = icon_size;
    obj.children[1].children[0] = new SFNode('Inline');
    obj.children[1].children[0].url[0] = url;
    
    obj.touch = new SFNode('TouchSensor');
    obj.children[1].children[1] = obj.touch;
    obj.button_click = NULL;
    obj.down = false;
    obj.over = false;
    obj.on_active = function(value) { 
     if (value) {
      this.down = true;
     } else {
      if (this.down && this.over && this.button_click) this.button_click(); 
      this.down = false;
     }
    };
    obj.button_over = on_icon_over;
    obj.on_over = function(value) { 
     this.over = value; 
     if (!no_back)
      this.children[0].scale.x = value ? 1 : 0;
     if (this.button_over) this.button_over(value); 
    };
    Browser.addRoute(obj.touch, 'isOver', obj, obj.on_over); 
    Browser.addRoute(obj.touch, 'isActive', obj, obj.on_active); 
    obj.label = label;
    obj.hide = function() { this.scale.x = this.scale.y = 0;};
    obj.show = function() { this.scale.x = this.scale.y = 1;};
    obj.set_size = function(x, y) { 
     this.children[0].children[0].set_size(x, y);
     this.children[1].size.x = x; 
     this.children[1].size.y = y;
    };
    return obj;
}

function text_label(label, justify)
{
    var obj = new SFNode('Transform2D');
    obj.children[0] = new SFNode('Shape');
    obj.children[0].appearance = new SFNode('Appearance');
    obj.children[0].appearance.material = new SFNode('Material2D');
    obj.children[0].appearance.material.filled = TRUE;
    obj.children[0].appearance.material.emissiveColor = new SFColor(0, 0, 0);
    obj.children[0].geometry = new SFNode('Text');
    obj.children[0].geometry.string[0] = label;
    obj.children[0].geometry.fontStyle = new SFNode('FontStyle');
    obj.children[0].geometry.fontStyle.justify[0] = justify;
    obj.children[0].geometry.fontStyle.justify[1] = 'MIDDLE';
    obj.children[0].geometry.fontStyle.size = 20;
    obj.set_label = function(value) {
     this.children[0].geometry.string[0] = value;
    };
    return obj;
}


function text_rect(label)
{
  var obj = new SFNode('Transform2D');
  obj.children[0] = rectangle();
  obj.children[0].set_color(0.7, 0.7, 0.8);

  obj.children[1] = new SFNode('Shape');
  obj.children[1].appearance = new SFNode('Appearance');
  obj.children[1].appearance.material = new SFNode('Material2D');
  obj.children[1].appearance.material.filled = TRUE;
  obj.children[1].appearance.material.emissiveColor = new SFColor(0, 0, 0);
  obj.children[1].geometry = new SFNode('Text');
  obj.children[1].geometry.string[0] = label;
  obj.children[1].geometry.fontStyle = new SFNode('FontStyle');
  obj.children[1].geometry.fontStyle.justify[0] = 'MIDDLE';
  obj.children[1].geometry.fontStyle.justify[1] = 'MIDDLE';
  obj.children[1].geometry.fontStyle.size = 20;
  obj.children[2] = new SFNode('TouchSensor');

  obj.set_size = function(w, h) { 
   this.children[0].set_size(w, h);
  };


  obj.over = false;
  obj.on_over = function(value) { 
    this.children[0].set_color(0.7, value ? 0.5 : 0.7, 0.8);
    this.over = value;
  };
  Browser.addRoute(obj.children[2], 'isOver', obj, obj.on_over); 

  obj.down = false;
  obj.button_click = null;
  obj.on_active = function(value) { 
   if (value) {
    this.down = true;
   } else {
    if (this.down && this.over && this.button_click) this.button_click(); 
    this.down = false;
   }
  };
  Browser.addRoute(obj.children[2], 'isActive', obj, obj.on_active); 

  return obj;  
}

function new_widget_control(widget)
{
  var obj = new SFNode('Transform2D');
  
  obj.children[0] = new SFNode('Transform2D');
  
  obj.children[0].children[0] = rectangle();

  obj.children[0].children[1] = new SFNode('TouchSensor');


  obj.component_bound=false;
  obj.show_ctrl = true;
  obj.onClick = function(value) {
   if (!value) return;
   this.show_ctrl = !this.show_ctrl;
   if (this.show_ctrl) {
    var i, comps, idx;
    this.children[0].children[0].appearance.material.transparency = 0;
    this.children[1].scale.x = 1;
    this.children[3].scale.x = 1;

    for (i=0; i<widget_display.children.length; i++) {
     if (widget_display.children[i]==this) continue;
     if (widget_display.children[i].show_ctrl) {
       widget_display.children[i].onClick(true);
      }
    }
    //widget is a component, do not push on top but hide some controls
    if (widget.is_component) {
     if (this.component_bound) {
      this.children[1].children[0].hide(); //close
      this.children[1].children[1].hide(); //remove
      this.children[1].children[4].hide(); //resize
     }
     return;
    }
    //otherwise push widget on top
    idx=0;
    widget_display.removeChildren[idx++] = this;
    widget_display.addChildren[idx++] = this;
    //and push components    
    comps = widget.components;
    for (i=0; i<comps.length; i++) {
     if (comps[i].widget_control.component_bound) {
      widget_display.removeChildren[idx++] = comps[i].widget_control;
      widget_display.addChildren[idx++] = comps[i].widget_control;
     }
    }
    
   } else {
    this.children[0].children[0].appearance.material.transparency = 1;
    this.children[1].scale.x = 0;
    this.children[3].scale.x = 0;
   }
  };
  Browser.addRoute(obj.children[0].children[1], 'isActive', obj, obj.onClick);
  
  obj.children[1] = new SFNode('Transform2D');
  obj.children[1].children[0] = icon_button('icons/process-stop.svg', 'Close', 0);
  obj.children[1].children[0].button_click = function() {
    if (widget.discardable) widget_remove(widget);
    else widget_close(widget, 0);
  };
  
  obj.children[1].children[1] = icon_button('icons/user-trash.svg', 'Uninstall', 0);
  obj.children[1].children[1].button_click = function() { widget_remove(widget);  }
  
  obj.children[1].children[2] = icon_button('icons/applications-internet.svg', 'Push to remote display', 0);
  obj.children[1].children[2].button_click = function() { 
    if (has_upnp && UPnP.MediaRenderersCount) {
     widget_remote_candidate = widget;
     on_upnpopen();
    }
  };

  obj.children[1].children[3] = icon_button('icons/dialog-information.svg', 'Widget Information', 0);
  obj.children[1].children[3].button_click = function() { 
   display_widget_info(widget);
  };

  obj.children[1].children[4] = icon_button('icons/media-record.svg', 'Resize', 1);
  obj.children[1].children[4].children[1].children[2] = new SFNode('PlaneSensor2D');  
  obj.children[1].children[4].children[1].children[2].maxPosition = new SFVec2f(-1, -1);

  obj.prev_x=0;
  obj.prev_y=0;
  obj.onSize = function(value) {
   if (widget.width + 2*(value.x - this.prev_x)<0) return;
   if (widget.height + 2*(this.prev_y-value.y)<0) return;
   
   widget.width += 2*(value.x - this.prev_x);
   this.prev_x = value.x;
   widget.height += 2*(this.prev_y - value.y);
   this.prev_y = value.y;
   this.set_size(widget.width, widget.height);
  };
  Browser.addRoute(obj.children[1].children[4].children[1].children[2], 'translation_changed', obj, obj.onSize);
  
  obj.children[2] = new SFNode('Layer2D');
  obj.inline = new SFNode('Inline');
  obj.children[2].children[0] = obj.inline;


  obj.children[3] = new SFNode('Transform2D');
  obj.children[3].children[0] = new SFNode('Shape');
  obj.children[3].children[0].appearance = new SFNode('Appearance');
  obj.children[3].children[0].appearance.material = new SFNode('Material2D');
  obj.children[3].children[0].appearance.material.filled = TRUE;
  obj.children[3].children[0].appearance.material.transparency = 0.5;
  obj.children[3].children[0].appearance.material.emissiveColor = new SFColor(0.6, 0.6, 0.6);
  obj.children[3].children[0].geometry = new SFNode('Rectangle');
  obj.children[3].children[0].geometry.size = new SFVec2f(50, 50);
  obj.children[3].children[1] = new SFNode('PlaneSensor2D');
  obj.children[3].children[1].maxPosition = new SFVec2f(-1, -1);
  obj.children[3].children[1].offset = new SFVec2f(widget.x, widget.y);  
  obj.onMove = function(value) {
   if (this.maximized) return;
   this.translation = value;
   widget.x = value.x;
   widget.y = value.y;
   this.refresh_layout(false, null);
  };
  Browser.addRoute(obj.children[3].children[1], 'translation_changed', obj, obj.onMove);

  obj.children[3].children[2] = new SFNode('TouchSensor');
  obj.last_ts = 0;
  obj.onMaximize = function(value, timestamp) {
   if (!value) return;
   if (timestamp - this.last_ts < 0.5) {
    if (this.maximized) {
     this.maximized = false; 
     this.translation.x = widget.x;
     this.translation.y = widget.y;
     this.set_size(this.prev_width, this.prev_height);
    } else {
     this.maximized = true;
     this.prev_width = widget.width;
     this.prev_height = widget.height;
     this.translation.x = 0;
     this.translation.y = -info_height;
     this.set_size(display_width, display_height - 2*info_height);
    }   
   }
   this.last_ts = timestamp;
  };
  Browser.addRoute(obj.children[3].children[2], 'isActive', obj, obj.onMaximize);

  obj.set_size = function(w, h) {
   var i, x, s;
   s = 24;
   this.children[2].size.x = w;
   this.children[2].size.y = h;
   
   this.children[1].children[0].translation.y = this.children[1].children[1].translation.y = this.children[1].children[2].translation.y = this.children[1].children[3].translation.y = this.children[1].children[4].translation.y = h/2 + s/2;

   this.children[0].children[0].set_size(w+s, h+s);
   this.children[3].children[0].geometry.size.x = w;
   this.children[3].children[0].geometry.size.y = h;

   this.children[1].children[0].set_size(s, s);
   this.children[1].children[1].set_size(s, s);
   this.children[1].children[2].set_size(s, s);
   this.children[1].children[3].set_size(s, s);
   this.children[1].children[4].set_size(s, s);
   this.children[1].children[0].translation.x = -w/2;
   this.children[1].children[1].translation.x = -w/4;
   this.children[1].children[2].translation.x = 0;
   this.children[1].children[3].translation.x = w/4;
   this.children[1].children[4].translation.x = w/2;

   //set widget input params
   widget.width = w;
   widget.height = h;
   widget.set_input('width', w);
   widget.set_input('height', h);
   this.refresh_layout(true, null);
   //call core:in
   WidgetManager.corein_message(widget, 'setSize', 'width', w, 'height', w, 'dpi', screen_dpi);
  };
  obj.refresh_layout = function(send_resize, comp_target) {
   var i;
   var x, y, w, h, scale_x, scale_y;
   var comps;

   /*local to subscene transformation not known*/
   if (!this.sub_w) return;
   if (!this.sub_h) return;

   comps = widget.components;
   for (i=0; i<comps.length; i++) {
    var comp = comps[i];
    if (!comp.widget_control.component_bound) continue;

    //compute scale from Widget Manager coord system to widget internal coordinate system
    scale_x = this.sub_vp_w / this.sub_w;
    scale_y = this.sub_vp_h / this.sub_h;

    w = comp.widget_control.place_w * scale_x;
    h = comp.widget_control.place_h * scale_y;
 
    x = this.translation.x - widget.width/2 + this.sub_vp_x + comp.widget_control.place_x * scale_x + w/2;
    comp.widget_control.translation.x = x;

    y = widget.height/2 + this.translation.y - h/2 - this.sub_vp_y - comp.widget_control.place_y * scale_y;
    comp.widget_control.translation.y = y;

    if (send_resize || (comp_target==comp)) 
     comp.widget_control.set_size(w, h);
   }
  };
  
  obj.hide = function() { 
   this.scale.x = 0;
   WidgetManager.corein_message(widget, 'hide');
  };
  obj.show = function() { 
    this.scale.x = 1; 
    WidgetManager.corein_message(widget, 'show');
  };

  obj.show_remote = function () {
   if (WidgetManager.upnp && UPnP.MediaRenderersCount) {
    this.children[1].children[2].show();
   } else {
    this.children[1].children[2].hide();
   }
  };
  obj.show_remove = function(show) {
    if (show) this.children[1].children[1].show();
    else this.children[1].children[1].hide();
  };

  obj.flash = function() {
    var time = new_timeout(0.25);
    time.loop = true;
    time.ctrl = this;
    time.on_event = function(val) {
     var scale = (val<0.5) ? 1+val : 2-val;
     this.ctrl.scale.x = this.ctrl.scale.y = scale;
    };
    time.stop(1);
    time.start(0);
  };
  obj.maximized = false;
  obj.show_remote();
  obj.onClick(true);
  return obj;
}



function on_icon_over(value)
{
 infobar.set_label(value ? this.label : '');
}

function display_widget_info(wid)
{
 var info_dlg = new SFNode('Transform2D');
 var i, j, k, info;
 var y, txt, pref;

 infobar.set_label('Widget ' + wid.name + ' Information');

 info = text_rect('Close');
 info_dlg.children[0] = info;
 info.button_click = function() {
  dlg_display.children.length = 0;
  widget_display.scale.x = 1;
  infobar.set_label('');
  layout();
 };
 
 info = text_rect('Widget Metadata');
 info_dlg.children[info_dlg.children.length] = info;
 info.visible = false;
 info.button_click = function() { 
   this.visible = !this.visible;
   layout();
 };
 i=3;
 info.children[i++] = text_label('id: ' + wid.identifier + ' - shortname: '+wid.shortName + ' - name: '+wid.name, 'BEGIN');
 info.children[i++] = text_label('version: '+wid.version, 'BEGIN');
 info.children[i++] = text_label('content type: ' + wid.mainMimeType + ' - content encoding: '+wid.mainEncoding, 'BEGIN');
 info.children[i++] = text_label('default size: Width = ' + wid.defaultWidth + ' Height = '+wid.defaultHeight, 'BEGIN');
 info.children[i++] = text_label('license: '+wid.license, 'BEGIN');
 info.children[i++] = text_label('license ref: '+wid.licenseHref, 'BEGIN');
 info.children[i++] = text_label('description: '+wid.description, 'BEGIN');
 info.children[i++] = text_label('author name: '+wid.authorName + ' (mail: '+wid.authorEmail+')', 'BEGIN');
 info.children[i++] = text_label('author href: '+wid.authorHref, 'BEGIN');
 info.children[i++] = text_label('view modes: '+wid.viewmodes, 'BEGIN');
 info.children[i++] = text_label('UUID: '+wid.uuid, 'BEGIN');
 info.children[i++] = text_label('Discardable: '+wid.discardable, 'BEGIN');
 info.children[i++] = text_label('Muliple Instances: '+wid.discardable, 'BEGIN');
 var icons = wid.icons;
 for (j=0; j<icons.length; j++) {
  info.children[i++] = text_label('icon #'+(j+1)+': ' + icons[j].src, 'BEGIN');
 }

 info = text_rect('Widget Manager Info');
 info_dlg.children[info_dlg.children.length] = info;
 info.visible = false;
 info.button_click = function() { 
   this.visible = !this.visible;
   layout();
 };
 i=3;
 info.children[i++] = text_label('nb instances: '+wid.num_instances + ' nb components: '+wid.num_components, 'BEGIN' );
 info.children[i++] = text_label('Permanently installed: '+wid.permanent + ' - is component: '+wid.is_component, 'BEGIN' );
 if (wid.is_component) {
   info.children[i++] = text_label('parent widget name' + wid.parent.name, 'BEGIN');
 }
 if (wid.originating_device_ip) {
  info.children[i++] = text_label('Widget was pushed from device IP '+wid.originating_device_ip, 'BEGIN' );
 }
 info.children[i++] = text_label('Section name in GPAC config file: '+wid.section, 'BEGIN' );
 info.children[i++] = text_label('UA Locale: ' + gpac.get_option('Systems', 'LanguageName') + ' (' + gpac.get_option('Systems', 'Language2CC') + ')', 'BEGIN');
 info.children[i++] = text_label('widget src: ' + wid.url , 'BEGIN');
 info.children[i++] = text_label('config src: ' + wid.manifest , 'BEGIN');
 info.children[i++] = text_label('content src : '+wid.localizedSrc, 'BEGIN' );

 pref = wid.features;
 info = text_rect('Features (' + pref.length + ')' ); 
 info_dlg.children[info_dlg.children.length] = info;
 info.visible = false;
 info.button_click = function() { 
   this.visible = !this.visible;
   layout();
 };
 i=3;
 for (j=0; j<pref.length; j++) {
  info.children[i++] = text_label('Feature #'+(j+1)+' name=\''+pref[j].name+'\' required=\''+pref[j].required+'\'', 'BEGIN');
 }


 pref = wid.preferences;
 info = text_rect('Preferences ('+pref.length+')'); 
 info_dlg.children[info_dlg.children.length] = info;
 info.visible = false;
 info.button_click = function() { 
   this.visible = !this.visible;
   layout();
 };
 i=3;
 for (j=0; j<pref.length; j++) {
  var val = pref[j].value;
  if (val == '') val = gpac.get_option(wid.section, pref[j].name);
  info.children[i++] = text_label('Preference #'+(j+1)+' name=\''+pref[j].name+'\' value=\''+val+'\' readOnly=\''+pref[j].readonly +'\'', 'BEGIN');
 }

 info = text_rect('Migration Context', 'BEGIN'); 
 info_dlg.children[info_dlg.children.length] = info;
 info.visible = false;
 info.button_click = function() { 
   this.visible = !this.visible;
   layout();
 };
 i=3;
 txt=wid.get_context();
 while (1) {
  var idx = txt.indexOf('\n', 0);
  if (idx>0) {
   info.children[i++] = text_label(txt.substring(0, idx), 'BEGIN'); 
   txt = txt.substring(idx+1, txt.length); 
  } else {
   info.children[i++] = text_label(txt, 'BEGIN'); 
   break;
  }
 }

 info_dlg.ifce_idx = info_dlg.children.length;
 info = text_rect('Interfaces (count: ' + wid.num_interfaces + ' - bound: ' + wid.num_bound_interfaces+')', 'BEGIN'); 
 info_dlg.children[info_dlg.ifce_idx] = info;
 info.visible = false;
 info.button_click = function() { 
   this.visible = !this.visible;
   layout();
 };
 i=3;
 for (j=0; j<wid.num_interfaces; j++) {
  var idx;
  var ifce = wid.get_interface(j);
  var item = text_rect('Interface #' + (j+1) + ' type: '+ifce.type);
  info.children[i++] = item;
  item.visible = false;
  item.button_click = function() { 
    this.visible = !this.visible;
    layout();
  };
  idx=3;
  item.children[idx++] = text_label('Multiple Binding: '+ifce.multipleBinding + ' - Service provider: '+ ifce.serviceProvider + ' - bound: ' + wid.is_interface_bound(ifce) , 'BEGIN');
  for (k=0; k<ifce.num_messages; k++) {
    var string, l;
    var msg = ifce.get_message(k);
    string = '  Message #'+ (k+1) + ':   ' + msg.name + '(';
    for (l=0; l<msg.num_params; l++) {
        par = msg.get_param(l);
        string += (par.is_input ? 'in' : 'out') + ':' +par.name + ' ';
    }
    string += ')';
    item.children[idx++] = text_label(string, 'BEGIN'); 
  }
 }
 
 info_dlg.set_size = function(w, h) {
  var i, j, y, dy;
  y = h/2 - 20;

  for (i=0; i<this.children.length; i++) {
   var item = this.children[i];
   item.translation.x = 0;
   item.translation.y = y;
   item.set_size(w, 20);
   y -= 20;
   if (!i) continue;
   
   dy = 0;
   for (j=3; j<item.children.length; j++) {
    if (item.visible) {
     item.children[j].scale.x = 1;
     dy -= 20;
     item.children[j].translation.y = dy;
     if (i<this.ifce_idx) {
      item.children[j].translation.x = -w/2+10;
     } else {
      item.children[j].set_size(w-20, 20);
      var ddy=0;
      var k, sitem;
      sitem = item.children[j];
      for (k=3; k<sitem.children.length; k++) {
       if (item.children[j].visible) {
        sitem.children[k].scale.x = 1;
        sitem.children[k].translation.x = -w/2+10;
        ddy -= 20;
        sitem.children[k].translation.y = ddy;
       } else {
        sitem.children[k].scale.x = 0;
       } 
      }
      dy+=ddy;
     }
    } else {
     item.children[j].scale.x = 0;
    }
   }
   y += dy;
  }
 };

 dlg_display.children[0] = info_dlg;
 widget_display.scale.x = 0;
 layout();
}


function widget_insert(widget)
{
  /*insert the widget icon*/
  if (widget.permanent && !widget.is_component)
    insert_widget_icon(widget, 0);
    
  /*and load the widget - comment this line to disable auto load of widget*/
  widget_launch(widget);
}

function setup_icons()
{
    var icon;
      
    //Widgets Icon
    icon = icon_button('icons/applications-system.svg', 'Available Widgets', 0);
    icon.button_click = function () {
     widget_screen_visible = !widget_screen_visible;
     layout();
    };
    dock.children[0] = icon;

    //Get Widget Icon
    icon = icon_button('icons/document-save.svg', 'Get Widget', 0);
    icon.button_click = function () {
     widget_get();
    };
    dock.children[1] = icon;

    //Widgets add Icon
    icon = icon_button('icons/list-add.svg', 'Add Widgets', 0);
    icon.button_click = function () {
     widget_browse();
    };
    dock.children[2] = icon;


    icon = icon_button('icons/user-trash.svg', 'Remove all widgets', 0);
    icon.button_click = function () {
      while (1) {
        var wid = WidgetManager.get(0);
        if (wid==null) break;
        widget_close(wid, 1);
      }
      widget_screen.children.length = 0;
      layout();
    };
    dock.children[3] = icon;

    //exit Icon
    icon = icon_button('icons/emblem-unreadable.svg', 'Exit', 0);
    icon.button_click = function() { gpac.exit(); };
    dock.children[4] = icon;
}



/*dock layout*/
function dock_layout() {
  var i;
      
  dock.translation.y = (dock_height - display_height)/2;
  infobar.translation.y = display_height/2 - info_height/2;
  
  num_in_dock = dock.children.length;
  tot_len = num_in_dock*icon_size;
  
  if (tot_len>display_width) {
   start_x = (icon_size-display_width)/2;
  } else {
   start_x = (icon_size-tot_len)/2;
  }
  /*translate / size all items in the dock*/
  for (i=0;i<num_in_dock; i++) {
   dock.children[i].set_size(icon_size, icon_size);
   dock.children[i].translation.x = start_x + i*icon_size;
  }
}

function widget_screen_layout(dir)
{
  var count, i, start_x, start_y, spread_x, nb_wid_h, nb_wid_v, nb_wid;
  
  if (!widget_screen_visible) {
    widget_screen.size.x = 0;
    widget_screen.size.y = 0;
    return;
  }

  widget_screen.size.x = display_width;
  widget_screen.size.y = display_height;

  start_x = (icon_size/2-display_width)/2;
  start_y = (display_height-icon_size/2)/2 - info_height;
  start_x = (icon_size-display_width)/2;
  start_y = (display_height-icon_size)/2 - icon_size/2 - info_height;
    
  count = widget_screen.children.length;
  if (first_visible_widget<0) first_visible_widget=0;
    
  for (i=0; i<count; i++) {
   var wid = widget_screen.children[i];
   wid.hide();
  }

  nb_wid_h = Math.floor(display_width / icon_size);
  if (!nb_wid_h) nb_wid_h=1;

  nb_wid_v = Math.floor((display_height-dock_height-icon_size) / icon_size);
  if (!nb_wid_v) nb_wid_v=1;
  
  spread_x = (display_width / nb_wid_h) - icon_size;
  start_x += spread_x/2;
  
  nb_wid = (nb_wid_h*nb_wid_v);
  if (dir<0) {
   first_visible_widget -= nb_wid;
   if (first_visible_widget < 0) first_visible_widget = 0;
  }
  else if (dir>0) {
   first_visible_widget += nb_wid;
  }
  
  for (i=0; i<count; i++) {
   var wid;
   if (i +first_visible_widget >= count) {
    break;
   }
   wid = widget_screen.children[i +first_visible_widget];
   wid.show();
   wid.set_size(icon_size, icon_size);
   wid.translation.x = start_x;
   wid.translation.y = start_y;
   start_x += icon_size + spread_x;
   if (start_x + icon_size / 2 >= display_width/2) {
    start_x = (icon_size-display_width)/2 + spread_x/2;
    start_y -= icon_size;
   }
   nb_widgets_on_screen = i+1;
   if (start_y - icon_size < (dock_height-display_height)/2) {
    i++;
    break;
   }
  }
}

//performs layout on all contents
function layout() {
  var i, list, start_x;

  gpac.set_option('Widgets', 'LastWMWidth', '' + display_width);
  gpac.set_option('Widgets', 'LastWMHeight', '' + display_height);


  if (WidgetManager.num_widgets) {
    dock.children[0].show();
  } else {
    dock.children[0].hide();
  }
  if (dlg_display.children.length) {
    widget_display.scale.x = 0;
    widget_screen_visible = false;
  }
  //layout all icons in the dock
  dock_layout();
  widget_screen_layout(0);

  if (dlg_display.children.length) {
    list = dlg_display.children;
    for (i=0; i<list.length; i++) {
     var dlg = list[i];
     if (typeof (dlg.set_size) != 'undefined') dlg.set_size(display_width, display_height-icon_size-info_height);
     dlg.translation.y = (icon_size-info_height)/2;
    }
  }
  else if (widget_screen_visible) {
    widget_display.scale.x = 0;
  } else {
    widget_display.scale.x = 1;
    list = widget_display.children;
    for (i=0; i<list.length; i++) {
     var widctrl = list[i];
     if (widctrl.maximized) {
      widctrl.translation.y = - info_height;
      widctrl.set_size(display_width, display_height - 2*info_height);
     }
    }
  }
}

//resize event callback
function on_resize(evt) {
    display_width = evt.width;
    display_height = evt.height;
    layout();
}
//zoom event callback
function on_zoom(evt) {
    display_width = evt.width;
    display_height = evt.height;
    layout();
}
//scroll event callback
function on_scroll(evt) {
  layout();
}

//starts a widget
function on_widget_launch() {
 if (this.widget.visible) {
  var awid;
  if (!this.widget.multipleInstances) return;
  awid = WidgetManager.open(this.widget.manifest, null);
  widget_launch(awid);
 } else {
   widget_launch(this.widget);
 }
}
      
function widget_get_icon(widget) 
{
  var icon = 'icons/process-stop.svg';
  var preferredIconType = '.svg';
  for (var i = 0; i < widget.icons.length; i++) {
      icon = widget.icons[i].relocated_src;
      if (widget.icons[i].relocated_src.indexOf(preferredIconType) > 0) {
          break;
      }
  }
 return icon;
}

//initialize GPAC widget manager and load all widgets
function widgets_init() {
    
    count = WidgetManager.num_widgets;      
    for (i=0; i<count; i++) {
     wid = WidgetManager.get(i);
     if (wid == null) continue;
     wid.device = null;
     wid.device_ip = null;
     if (wid.in_panel == true) {
       icon = icon_button(widget_get_icon(wid), wid.name, 0);
       icon.tooltip = wid.name;
       icon.widget = wid;
       icon.button_click = on_widget_launch;
  
       wid.icon_dock = icon;
       widget_screen.children[widget_screen.children.length] = wid.icon_dock;
     }
     if (wid.visible) {
      widget_launch(wid);
     }        
    }
}

function on_widget_size(value) {
  //remember variables
  this.width = value.x;
  this.height = value.y;
  //and set widget input params
  this.set_input('width', value.x);
  this.set_input('height', value.y);
}

function on_widget_move(value) {
  this.x = value.x;
  this.y = value.y;
}

//widget close function
function widget_close(widget, force_remove) 
{
    var is_comp = widget.is_component;
    if (widget.visible) {
      widget.visible = false;
      WidgetManager.corein_message(widget, 'hide');
      WidgetManager.corein_message(widget, 'deactivate');
      widget.deactivate();
      widget.scene_container.removeChildren[0] = widget.widget_control;
      /*force disconnect of main resource - we do this because we are not sure when the widget_control will be destroyed due to JS GC*/
      widget.widget_control.inline.url.length = 0;
    }
    if (!is_comp && (!widget.permanent || force_remove)) {
      WidgetManager.unload(widget, false);
    }
}
   
function on_widget_close(value) {
    widget_close(this, 0);
}
   
//widget remove function (close and unregister)
function widget_remove(wid) {
  if (typeof(wid.icon_dock) != 'undefined')
    widget_screen.removeChildren[0] = wid.icon_dock;
  widget_close(wid, 0);
  layout();
}

function on_widget_control(value)
{
 var i, count;
 if (!value) return;
 count = this.scene_container.children.length;
 for (i=0; i<count; i++) {
  if (this.scene_container.children[i] == this.widget_control) {
   this.scene_container.removeChildren[0] = this.widget_control;
   this.scene_container.children[this.scene_container.children.length] = this.widget_control;
   return;
  }
 }
}

//widget launcher function
function widget_launch(wid) {
    var widg_ctrl;

   //assign default size to the widget
   if (wid.width == undefined) {
    wid.width = wid.defaultWidth;
    if (wid.width == 0) wid.width = widget_default_size;
   }
   if (wid.height == undefined) {
    wid.height = wid.defaultHeight;
    if (wid.height == 0) wid.height = widget_default_size;
   }
   if (wid.x== undefined) wid.x = 0;
   if (wid.y== undefined) wid.y = 0;

   widg_ctrl = new_widget_control(wid);
   widg_ctrl.component_bound = false;

   wid.visible = true;

   widg_ctrl.set_size(wid.width, wid.height);
   widg_ctrl.translation.x = wid.x;
   widg_ctrl.translation.y = wid.y;
    
   wid.widget_control = widg_ctrl;
   wid.scene_container = widget_display;

   widg_ctrl.show_remove( (!wid.discardable && wid.icon_dock) ? 1 : 0);

   widg_ctrl.sub_width = 0;
   widg_ctrl.sub_height = 0;
   widg_ctrl.sub_x = 0;
   widg_ctrl.sub_y = 0;
   widg_ctrl.sub_vp_w = 0;
   widg_ctrl.sub_vp_h = 0;

   widg_ctrl.inline.addEventListener('gpac_vp_changed', 
                                  function(evt) { 
                                   widg_ctrl.sub_vp_w = evt.width;
                                   widg_ctrl.sub_vp_h = evt.height;
                                   widg_ctrl.sub_vp_x = evt.offset_x;
                                   widg_ctrl.sub_vp_y = evt.offset_y;
                                   widg_ctrl.sub_w = evt.vp_width;
                                   widg_ctrl.sub_h = evt.vp_height;
                                   widg_ctrl.refresh_layout(true, null);
                                  }, 
                                0);
    
   /*this will setup the scene graph for the widget in order to filter input and output communication pins*/
   wid.activate(widg_ctrl.inline);

   widg_ctrl.inline.url[0] = wid.main;
   widget_display.addChildren[0] = widg_ctrl;

    /*send notifications once the widget scene is loaded*/
    wid.on_load = function () {
      WidgetManager.corein_message(this, 'activate');
      WidgetManager.corein_message(this, 'show');
      WidgetManager.corein_message(this, 'setSize', 'width', 50, 'height', 50, 'dpi', 96);
    };

  if (widget_screen_visible) {
   widget_screen_visible = 0;
   layout();
  }
    //
    if (log_level > l_inf) {
        var i = 0;
        alert(">>>>>>>>>>>>> "+wid.name+" interfaces:");
        for (;i < wid.num_interfaces; i++) {
            alert(""+wid.get_interface(i).type);
        }
    }
    //
}


//core out install widget implementation JCD
function widget_install_widget(widget, args)
{
    var uri = args[0], j;
    var count = WidgetManager.num_widgets;
    for (j=0; j<count; j++) {
        var wid = WidgetManager.get(j);
        if (wid.url==uri) break;
    }
    if (j==count) {
        new_wid = WidgetManager.open(uri, null);
        if (new_wid!=null) {
            insert_widget_icon(new_wid, 1);
        }
    }
}

//core out migrate component implementation JCD
function widget_migrate_component(widget, args)
{
    if (has_upnp && UPnP.MediaRenderersCount) {
        widget_remote_candidate = widget.get_component(args[0]);
        if (widget_remote_candidate==null) {
         log(l_err, 'Component '+args[0]+' cannot be found in widget '+widget.name);
         return;
        }
        if (args.length > 1 && args[1] != null) {
            var render = WidgetManager.MPEGUStandardServiceProviders[parseInt(args[1])];
            WidgetManager.migrate_widget(render, widget_remote_candidate);
            widget_close(widget_remote_candidate, 0);
            widget_remote_candidate = null;
        } else {
            on_upnpopen();
        }
    }
}

// core out request migration targets JCD
function widget_request_migration_targets(wid, args)
{
    var count = WidgetManager.MPEGUStandardServiceProviders.length,
        codes = new Array(), names = new Array(), descriptions = new Array(), i;
    for (i = 0; i < count; i++) {
        var render = WidgetManager.MPEGUStandardServiceProviders[i];
        codes.push(""+i);
        names.push(render.Name);
        descriptions.push(render.HostName +" "+ render.UUID);
    }
    i = null;
    var ifce_count = wid.num_interfaces, j;
    for (j = 0; j < ifce_count; j++) {
        var ifce = wid.get_interface(j);
        if (ifce.type == "urn:mpeg:mpegu:schema:widgets:core:out:2010") {
            i = ifce;
            break;
        }
    }
    if (i != null) {
        wmjs_core_out_invoke_reply(coreOut.requestMigrationTargetsMessage, i.get_message("requestMigrationTargets"),
                wid, codes, names, descriptions);
    }

}

function widget_request_size(widget, args)
{
  if (args.length==2) {
   w = (typeof args[0] == 'string') ? parseInt(args[0]) : args[0];
   h = (typeof args[1] == 'string') ? parseInt(args[1]) : args[1];
   widget.widget_control.set_size(w, h);
  }
}

function widget_request_show(widget, args)
{
 widget.widget_control.show();
}

function widget_request_hide(widget, args)
{
 widget.widget_control.hide();
}

function widget_request_activate(widget, args)
{
 if (!widget.visible)
  widget_launch(widget);
}

function widget_request_deactivate(widget, args)
{
 if (widget.visible)
  widget_close(widget, 0);
}

function widget_request_attention(widget, args)
{
 if (widget.visible) {
  widget_display.removeChildren[0] = widget.widget_control;
  widget_display.addChildren[0] = widget.widget_control;
  widget.widget_control.flash();
 }
}

function widget_request_notification(widget, args)
{
 var notif = text_rect('');
 notif.children[1].geometry.string[0] = 'Notification from widget';
 notif.children[1].geometry.string[1] = ' '+widget.name;
 notif.children[1].geometry.string[2] = ' ';
 notif.children[1].geometry.string[3] = args[0];
 dlg_display.children[0] = notif;
 notif.set_size(320, 240);
 notif.button_click = function() {
  dlg_display.removeChildren[0] = this;
 } 
}

function widget_place_component(widget, args)
{
 var comp = widget.get_component(args[0]);
 
 if (comp==null) {
  log(l_err, 'Component '+args[0]+' cannot be found in widget '+widget.name);
  return;
 }
 comp.widget_control.place_x = args[1];
 comp.widget_control.place_y = args[2];
 comp.widget_control.place_w = args[3];
 comp.widget_control.place_h = args[4];
 comp.widget_control.place_z = args[5];
 comp.widget_control.component_bound = true;
 widget.widget_control.refresh_layout(false, comp);
}

 
     
function insert_widget_icon(new_wid, no_layout) {
 var icon;
 icon = icon_button(widget_get_icon(new_wid), new_wid.name, 0);
 icon.tooltip = new_wid.name;
 new_wid.in_panel = true;
 new_wid.visible = false;
 new_wid.icon_dock = icon;
 icon.button_click = on_widget_launch;
 icon.widget = new_wid;
 widget_screen.addChildren[0] = new_wid.icon_dock; 
 if (!no_layout) layout();    
}

function scan_directory(dir)
{
  var i, j, count, list, new_wid, uri;
  list = gpac.enum_directory(dir, '.xml;.wgt;.mgt', 0);
  for (i=0; i<list.length; i++) {
   uri = list[i].path + list[i].name;
   if (list[i].directory) {
    scan_directory(uri);
   } else {
    count = WidgetManager.num_widgets;
    for (j=0; j<count; j++) {
     var wid = WidgetManager.get(j);
     if (wid.url==uri) break;
    }
    if (j==count) {
     new_wid = WidgetManager.open(uri, null);
     if (new_wid!=null) {
      insert_widget_icon(new_wid, 1);
     }
    }
   }
  }
}

function widget_browse()
{
  filebrowse = new SFNode('Transform2D');
  infobar.set_label('Select widget');
  dlg_display.children[0] = filebrowse;
  
  filebrowse.children[0] = icon_button('icons/emblem-unreadable.svg', 'Close', 0);
  filebrowse.children[0].button_click = function() {
   dlg_display.children.length = 0;
   widget_display.scale.x = 1;
   layout();
  }
  
  filebrowse.children[1] = icon_button('icons/go-previous.svg', 'Previous', 0);
  filebrowse.children[1].filebrowse = filebrowse;
  filebrowse.children[1].button_click = function () { this.filebrowse.layout(0) };
  
  filebrowse.children[2] = icon_button('icons/go-next.svg', 'Next', 0);
  filebrowse.children[2].filebrowse = filebrowse;
  filebrowse.children[2].button_click = function () { this.filebrowse.layout(1) };
  
  filebrowse.children[3] = icon_button('icons/go-up.svg', 'Up', 0);
  filebrowse.children[3].filebrowse = filebrowse;
  filebrowse.children[3].button_click = function () { this.filebrowse.browse(true) };
  
  filebrowse.children[4] = icon_button('icons/Folder.svg', 'Scan Directory', 0);
  filebrowse.children[4].filebrowse = filebrowse;
  filebrowse.children[4].button_click = function () {
   scan_directory(this.filebrowse.directory);
   WidgetManager.last_widget_dir = this.filebrowse.directory;
   dlg_display.children.length = 0;
   widget_display.scale.x = 0;
   widget_screen_visible = true;
   layout();
  }
  filebrowse.children[5] = text_label('', 'BEGIN');
  filebrowse.set_label = function(label) {
    filebrowse.children[5].set_label(label);
  }
  filebrowse.nb_tools = filebrowse.children.length;

  filebrowse.browse = function(go_up) {
   this.list = gpac.enum_directory(this.directory, '*.xml;*.wgt;*.mgt', go_up);
   if (this.list.length) {
    this.directory = this.list[0].path;
    this.set_label(this.directory);
   } else {
    this.set_label('');
   }
   this.first = 0;
   this.layout(0);
  }
  filebrowse.layout = function(type) {
   var w, h, i, y;
   this.children.length = this.nb_tools;

   this.children[1].hide();
   this.children[2].hide();
   if (this.directory == '') 
    this.children[3].hide();
   else
    this.children[3].show();

   if (type==0) {
    this.first -= this.nb_items;
    if (this.first<0) this.first = 0;
   }
   else if (type) {
    this.first += this.nb_items;
    if (this.first + this.nb_items > this.list.length) this.first = this.list.length - this.nb_items;
   }
   if (this.first) this.children[1].show();
   if (this.first+this.nb_items < this.list.length) this.children[2].show();

   for (i=0; i<this.nb_items; i++) {
    var item;
    if (i+this.first>=this.list.length) break;
    item = text_rect(this.list[i+this.first].name);
    item.path = this.list[i+this.first].path;
    item.name = this.list[i+this.first].name;
    item.directory = this.list[i+this.first].directory;
    item.filebrowse = this;
    item.button_click = function() {
     if (this.directory) {
      this.filebrowse.directory = this.path + this.name;
      this.filebrowse.browse(false);
     } else {
      var value = this.path + this.name;
      dlg_display.children.length = 0;
      widget_display.scale.x = 1;
      widget_screen_visible = true;
      layout();

      var new_wid = WidgetManager.open(value, null);
      if (new_wid==null) return;

      WidgetManager.last_widget_dir = this.filebrowse.directory;
      insert_widget_icon(new_wid, 0);
     }
    }
    this.children[this.nb_tools+i] = item;
   }   
   this.set_size(this.width, this.height);
  }
  
  
  filebrowse.set_size = function(w, h) {
   var i, x, y, isize, nbi;
   isize = 24;
   if (w>display_width - isize) w = display_width - isize;

   this.width = w;
   this.height = h;

   i = 1;
   while ((i+1)*isize <= h - isize) i++;
   
   if (i != this.nb_items) {
    this.nb_items = i;
    this.layout(0);
    return;
   }
   x = -w/2 + isize/2;
   y = h/2 - isize/2;

   for (i=0;i<this.nb_tools;i++) {
     if (this.nb_tools>i+1) {
       this.children[i].set_size(isize, isize);
     }
     this.children[i].translation.x = x;
     this.children[i].translation.y = y;
     x += isize;
   }
   y-=isize;
   while (i<this.children.length) {
     this.children[i].set_size(w, isize);
     this.children[i].translation.x = 0;
     this.children[i].translation.y = y;
     y-=isize;
     i++;
   }
  }  
  filebrowse.nb_items = 0;
  filebrowse.directory = WidgetManager.last_widget_dir;
  filebrowse.browse(0);

  widget_display.scale.x = 0;
  layout();
}

function onMediaRendererAdd(name, uuid, is_add)
{
 var i, count;

 count = WidgetManager.num_widgets;
 for (i=0; i<count; i++) {
  wid = WidgetManager.get(i);
  if (wid == null) continue;
  if (!wid.widget_control) continue;
  wid.widget_control.show_remote();
 }

 if (upnp_renders) upnp_renders.refresh();
}

function on_upnpopen()
{
  upnp_renders = new SFNode('Transform2D');
  upnp_renders.nb_items = 0;
  upnp_renders.refresh = function () {
    var i, count, render, item, start_y, w;
    this.children.length = 0;
    count = WidgetManager.MPEGUStandardServiceProviders.length;
    if (count+1>this.nb_items) count = this.nb_items-1;

    item = text_rect('Close');
    item.button_click = function() {
     dlg_display.children.length = 0;
     upnp_renders=null;
     widget_display.scale.x = 1;
     infobar.set_label('');
    }
    this.children[this.children.length] = item;

    for (i=0; i<count; i++) {
      render = WidgetManager.MPEGUStandardServiceProviders[i];
      item = text_rect(render.Name);
      item.render = render;
  
      item.button_click = function() {
       dlg_display.children.length = 0;
       upnp_renders=null;
       widget_display.scale.x = 1;
       infobar.set_label('');
  
       WidgetManager.migrate_widget(this.render, widget_remote_candidate);
       widget_close(widget_remote_candidate, 0);
       widget_remote_candidate = null;   
      }  
      this.children[this.children.length] = item;
    }
    this.set_size(this.width, this.height);
  }

  upnp_renders.set_size = function (w, h) {
    var i, count, start_y, w;   

    this.width = w<300 ? w : 300;
    this.height = h;
    
    i = 1;
    while ((i+1)*icon_size <= h - icon_size) i++;
    if (i != this.nb_items) {
      this.nb_items = i;
      this.refresh();
      return;
    }
    count = this.children.length;
    start_y = this.height/2 - icon_size - 4;
    for (i=0; i<count; i++) {
      this.children[i].set_size(this.width, icon_size);
      this.children[i].translation.y = start_y;
      start_y-=icon_size+2;
    }
  }

  infobar.set_label('Select remote display');
  dlg_display.children[0] = upnp_renders;
  widget_display.scale.x = 0;
  layout();
}


function onMediaConnect(url, src_ip)
{
 if (WidgetManager.probe(url)) {
  var new_wid = WidgetManager.open(url, src_ip);
  if (new_wid==null) {
   return;
  }
  widget_insert(new_wid); 
 }
}

// widget get: UI for listWidgets and getWidget
// added by Jean-Claude Dufourd, modeled on filebrowse
function widget_get() {
    alert("widget_get");
    widgetbrowse = new SFNode('Transform2D');
    infobar.set_label('Select widget manager');
    dlg_display.children[0] = widgetbrowse;

    widgetbrowse.children[0] = icon_button('icons/emblem-unreadable.svg', 'Close', 0);
    widgetbrowse.children[0].button_click = function() {
        dlg_display.children.length = 0;
        widget_display.scale.x = 1;
        layout();
    };

    widgetbrowse.children[1] = text_label('', 'BEGIN');
    widgetbrowse.set_label = function(label) {
        widgetbrowse.children[1].set_label(label);
    };

    widgetbrowse.nb_tools = widgetbrowse.children.length;

    // this function builds the whole UI the first time
    widgetbrowse.layout = function() {
        alert("widgetbrowse.layout");
        var w, h, i, y;
        this.children.length = this.nb_tools;
        for (i = 0; i < this.nb_items; i++) {
            var item;
            if (i >= this.list.length) {
                break;
            }
            item = text_rect(this.list[i].Name);
            item.wm = this.list[i];
            item.widgetbrowse = this;
            item.button_click = function() {
                alert("click to select wm: "+this.wm.Name);
                this.widgetbrowse.wm = this.wm;
                this.wm.standardService.SetActionListener("listWidgets", get_widget_callback(this.wm, this.widgetbrowse), true);
                this.wm.standardService.CallAction("listWidgets", new Array());
            };
            this.children[this.nb_tools + i] = item;
        }
        this.set_size(this.width, this.height);
    };

    widgetbrowse.set_size = function(w, h) {
        alert("widgetbrowse.set_size "+w+" "+h);
        var i, x, y, isize, nbi;
        isize = 24;
        if (w > display_width - isize) {
            w = display_width - isize;
        }
        this.width = w;
        this.height = h;
        i = 1;
        while ((i + 1) * isize <= h - isize) {
            i++;
        }
        if (i != this.nb_items) {
            this.nb_items = i;
            this.layout(0);
            return;
        }
        x = -w / 2 + isize / 2;
        y = h / 2 - isize / 2;
        for (i = 0; i < this.nb_tools; i++) {
            if (this.nb_tools > i + 1) {
                this.children[i].set_size(isize, isize);
            }
            this.children[i].translation.x = x;
            this.children[i].translation.y = y;
            x += isize;
        }
        y -= isize;
        while (i < this.children.length) {
            this.children[i].set_size(w, isize);
            this.children[i].translation.x = 0;
            this.children[i].translation.y = y;
            y -= isize;
            i++;
        }
    };

    widgetbrowse.nb_items = WidgetManager.MPEGUStandardServiceProviders.length;
    widgetbrowse.list = WidgetManager.MPEGUStandardServiceProviders;
    widgetbrowse.set_label('Select Widget Manager');
    widgetbrowse.layout(0);
    widget_display.scale.x = 0;
    layout();
}

function get_widget_callback(device, widgetbrowse) {
    alert("get_widget_callback "+device.Name+" "+widgetbrowse);
    return function() {
        // msgHandler is the first argument, the next arguments are from the reply to listWidgets
        var act = arguments[0];
        var act1 = act.GetArgumentValue("widgetCodes");
        var act2 = act.GetArgumentValue("widgetNames");
        alert("callback |"+act1+"| |"+act2+"|");
        widgetbrowse.set_label("Select Widget");
        var w, h, i, y;
        act1 = act1.split(" ");
        act2 = act2.split(" ");
        widgetbrowse.children.length = widgetbrowse.nb_tools;
        for (i = 0; i < act2.length; i++) {
            if (act1[i]=="" || act2[i]=="") continue;
            var item = text_rect(act2[i]);
            item.widgetCode = act1[i];
            item.widgetName = act2[i];
            item.widgetbrowse = widgetbrowse;
            item.button_click = function() {
                alert("selected widget: "+this.widgetName);
                dlg_display.children.length = 0;
                widget_display.scale.x = 1;
                widget_screen_visible = true;
                layout();
                var arr = new Array();
                arr[0] = "widgetCode";
                arr[1] = this.widgetCode;
                this.widgetbrowse.wm.standardService.SetActionListener("getWidget", get_widget_callback2, true);
                this.widgetbrowse.wm.standardService.CallAction("getWidget", arr);
            };
            widgetbrowse.children[this.nb_tools + i] = item;
        }
        widgetbrowse.set_size(widgetbrowse.width, widgetbrowse.height);
    }
}

function get_widget_callback2() {
    // msgHandler is the first argument, the next arguments are from the reply to listWidgets
    alert("callback2-1");
    var act = arguments[0];
    var act1 = act.GetArgumentValue("widgetUrl");
    var act2 = act.GetArgumentValue("widgetContext");
    alert("callback2-2 " + act1 + " " + act2);
    var wid = WidgetManager.load(act1, null, act2);
    WidgetManager.on_widget_add(wid);
}
